package com.dadovicn.repo.primary.fx.imp;

import com.dadovicn.enums.MonthOfYearEnum;
import com.dadovicn.enums.ReportEnum;
import com.dadovicn.fx.jcb.dsl.QJcbBjBjlbb;
import com.dadovicn.fx.ywb.dsl.QYwbJqCjjlb;
import com.dadovicn.fx.ywb.dsl.QYwbJqJjjlb;
import com.dadovicn.fx.ywb.dto.PieDTO;
import com.dadovicn.fx.ywb.vo.ReportVO;
import com.dadovicn.fx.ywb.vo.XqVO;
import com.dadovicn.repo.primary.base.BaseQueryDsl;
import com.dadovicn.repo.primary.fx.CommonRepo;
import com.dadovicn.repo.primary.fx.JjAnalysisRepo;
import com.dadovicn.web.Result;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.StringTemplate;
import com.querydsl.jpa.impl.JPAQuery;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.IntStream;

/**
 * 接警数据分析
 * @author dadovicn
 * @date   2018/10/4
 */
@Slf4j
@Component
@Transactional
public class JjAnalysisRepoImpl extends BaseQueryDsl implements JjAnalysisRepo {
    /// todo 0003 优化建议: 一次性查出来, 搜索list统计, 减少数据库操作.
    /// todo 0004 优化建议: 后期转此接口为定时统计, 结果放缓存.
    @Resource
    private CommonRepo commonRepo;

    @Override
    @Cacheable(value = "reportCache", key = "#root.methodName")
    public Result getReportYearMonth() {
        Map<String, Object> withXq = new HashMap<>();
        List<XqVO> listAllXq = commonRepo.listAllXq(); //所有辖区
        for(XqVO xqVO: listAllXq) {
            yearMonth(withXq, xqVO);
        }
        yearMonth(withXq, null);
        return Result.success(withXq);
    }

    private void yearMonth(Map<String, Object> withXq, XqVO xqVO) {
        String year = String.valueOf(LocalDate.now().getYear());
        List<ReportVO> result = new ArrayList<>();
        Arrays.stream(MonthOfYearEnum.values()).forEach(i -> {
            ReportVO reportVO;
            StringTemplate tmp = Expressions.stringTemplate("TO_CHAR({0},'yyyy-mm')", QYwbJqJjjlb.ywbJqJjjlb.bjsj);
            BooleanBuilder booleanBuilder = new BooleanBuilder();
            if (i.getValue() < 10) {
                booleanBuilder.and(tmp.eq(year + "-0" + String.valueOf(i.getValue())));
                reportVO = getReportByTime(booleanBuilder, xqVO == null ? null : xqVO.getXqdm());
                result.add(reportVO);
            } else {
                booleanBuilder.and(tmp.eq(year + "-" + String.valueOf(i.getValue())));
                reportVO = getReportByTime(booleanBuilder, xqVO == null ? null : xqVO.getXqdm());
                result.add(reportVO);
            }
        });
        withXq.put(xqVO == null ? "all" : xqVO.getXqmc(), result);
    }

    @Override
    public ReportVO getReportByTime(BooleanBuilder builder, String xqdm) {
        QYwbJqJjjlb jj = QYwbJqJjjlb.ywbJqJjjlb;
        QYwbJqCjjlb cj = QYwbJqCjjlb.ywbJqCjjlb;
        if(xqdm != null) {
            builder.and(jj.xqdm.eq(xqdm));
        }
        JPAQuery jpaQuery = queryFactory.select(jj.jjbh).where(builder).from(jj).fetchAll();
        Long jjTotal = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder)).fetchAll();
        Long validTotal = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.jjbjlb.eq(ReportEnum.XSAJ.getValue()))).fetchAll();
        Long xsajTotal = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.jjbjlb.eq(ReportEnum.XSAJ.getValue())).and(jj.jjbjlx.eq(ReportEnum.DAOQIE.getValue()))).fetchAll();
        Long daoqie = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.jjbjlb.eq(ReportEnum.XSAJ.getValue())).and(jj.jjbjlx.eq(ReportEnum.QIANGJIE.getValue()))).fetchAll();
        Long qiangjie = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.jjbjlb.eq(ReportEnum.XSAJ.getValue())).and(jj.jjbjlx.eq(ReportEnum.QIANGDUO.getValue()))).fetchAll();
        Long qiangduo = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.jjbjlb.eq(ReportEnum.XSAJ.getValue())).and(jj.jjbjlx.eq(ReportEnum.ZHAPIAN.getValue()))).fetchAll();
        Long zhapian = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.jjbjlb.eq(ReportEnum.XSAJ.getValue())).and(jj.jjbjlx.eq(ReportEnum.QIAOZHAOLESUO.getValue()))).fetchAll();
        Long qiaozhalesuo = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.jjbjlb.eq(ReportEnum.XSAJ.getValue())).and(jj.jjbjlx.eq(ReportEnum.SHANGHAI.getValue()))).fetchAll();
        Long shanghai = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.jjbjlb.eq(ReportEnum.XSAJ.getValue())).and(jj.jjbjlx.eq(ReportEnum.SHAREN.getValue()))).fetchAll();
        Long sharen = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.jjbjlb.eq(ReportEnum.XSAJ.getValue())).and(jj.jjbjlx.eq(ReportEnum.QIANGJIAN.getValue()))).fetchAll();
        Long qiangjian = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.jjbjlb.eq(ReportEnum.XSAJ.getValue())).and(jj.jjbjlx.eq(ReportEnum.SHEDUANJIAN.getValue()))).fetchAll();
        Long sheduanjian = jpaQuery.fetchCount();
        Long qitaxingshi = xsajTotal - daoqie - qiangjie - qiangduo - zhapian - qiaozhalesuo - shanghai - sharen - qiangjian - sheduanjian;


        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.jjbjlb.eq(ReportEnum.ZHIAN.getValue()))).fetchAll();
        Long zhian = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.jjbjlb.eq(ReportEnum.QUNZHONG.getValue()))).fetchAll();
        Long qunzhong = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.jjbjlb.eq(ReportEnum.JIAOTONG.getValue()))).fetchAll();
        Long jiaotong = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.jjbjlb.eq(ReportEnum.HUOZAI.getValue()))).fetchAll();
        Long huozai = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.jjbjlb.eq(ReportEnum.JUBAOTOUSU.getValue()))).fetchAll();
        Long jubaotousu = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.jjbjlb.eq(ReportEnum.SHEHUI.getValue()))).fetchAll();
        Long shehui = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.jjbjlb.eq(ReportEnum.QUNTI.getValue()))).fetchAll();
        Long qunti = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.jjbjlb.eq(ReportEnum.ZAIHAI.getValue()))).fetchAll();
        Long zaihai = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.jjbjlb.eq(ReportEnum.XINGZHENG.getValue()))).fetchAll();
        Long xingzheng = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.jjbjlb.eq(ReportEnum.QITA.getValue()))).fetchAll();
        Long qita = jpaQuery.fetchCount();

        Long inValidTotal = jjTotal - validTotal;

        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.lhlbdm.eq(ReportEnum.BAOJINGQIUZHU.getValue()))).fetchAll();
        Long baojingqiuzhu = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.lhlbdm.eq(ReportEnum.QUNZHONGTOUSU.getValue()))).fetchAll();
        Long qunzhongtousu = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.lhlbdm.eq(ReportEnum.SHEHUILIANDONG.getValue()))).fetchAll();
        Long shehuiliandong = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.lhlbdm.eq(ReportEnum.CHUJINGFANKUI.getValue()))).fetchAll();
        Long chujingfankui = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.lhlbdm.eq(ReportEnum.GONGZUOZIXUN.getValue()))).fetchAll();
        Long gongzuozixun = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.lhlbdm.eq(ReportEnum.XUJIAJINGQING.getValue()))).fetchAll();
        Long xujiajingqing = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.lhlbdm.eq(ReportEnum.WULIYAOQIU.getValue()))).fetchAll();
        Long wuliyaoqiu = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.lhlbdm.eq(ReportEnum.CHONGFUBAOJING.getValue()))).fetchAll();
        Long chongfubaojing = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.lhlbdm.eq(ReportEnum.SAORAODIANHUA.getValue()))).fetchAll();
        Long saoraodianhua = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.lhlbdm.eq(ReportEnum.XITONGCESHI.getValue()))).fetchAll();
        Long xitongceshi = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.lhlbdm.eq(ReportEnum.QITALEIXING.getValue()))).fetchAll();
        Long qitaleixing = jpaQuery.fetchCount();
        jpaQuery = queryFactory.select(jj.jjbh).from(jj, cj).where(jj.jjbh.eq(cj.jjbh).and(builder).and(jj.lhlbdm.eq(ReportEnum.WUXIAO.getValue()))).fetchAll();
        Long wuxiao = jpaQuery.fetchCount();

        Long lhlbTotal = baojingqiuzhu + qunzhongtousu + shehuiliandong + chujingfankui + gongzuozixun + xujiajingqing + wuliyaoqiu + chongfubaojing + saoraodianhua + xitongceshi + qitaleixing + wuxiao;

        ReportVO reportVO = new ReportVO(jjTotal,validTotal,xsajTotal,daoqie,qiangjie,qiangduo,zhapian,qiaozhalesuo,shanghai,sharen,qiangjian,sheduanjian,qitaxingshi,
                zhian,qunzhong,jiaotong,huozai,jubaotousu,shehui,qunti,zaihai,xingzheng,qita,inValidTotal,
                baojingqiuzhu,qunzhongtousu,shehuiliandong,chujingfankui,gongzuozixun,xujiajingqing,wuliyaoqiu,chongfubaojing,saoraodianhua,xitongceshi,qitaleixing,wuxiao, lhlbTotal);

        return reportVO;
    }

    @Override
    @Cacheable(value = "reportCache", key = "#root.methodName")
    public Result getReportMonthDay() {
        Map<String, Object> withXq = new HashMap<>();
        List<XqVO> listAllXq = commonRepo.listAllXq(); //所有辖区
        for(XqVO xqVO: listAllXq) {
            monthDay(withXq, xqVO);
        }
        monthDay(withXq, null);
        return Result.success(withXq);
    }

    private void monthDay(Map<String, Object> withXq, XqVO xqVO) {
        String year = String.valueOf(LocalDate.now().getYear());
        List<ReportVO> result = new ArrayList<>();
        LocalDate now = LocalDate.now();
        // 当前月份
        String month = String.valueOf(now.getMonth().getValue());
        Integer leg = now.lengthOfMonth();
        IntStream.range(1, now.getDayOfMonth()).forEach(i -> {
            ReportVO reportVO;
            StringTemplate tmp = Expressions.stringTemplate("TO_CHAR({0},'yyyy-mm-dd')", QYwbJqJjjlb.ywbJqJjjlb.bjsj);
            BooleanBuilder booleanBuilder = new BooleanBuilder();
            if(i < 10) {
                booleanBuilder.and(tmp.eq(year + (month.length() == 1 ? "-0" + month : "-" + month) + "-0" + String.valueOf(i)));
                reportVO = getReportByTime(booleanBuilder, xqVO == null ? null : xqVO.getXqdm());
                result.add(reportVO);
            }else {
                booleanBuilder.and(tmp.eq(year + (month.length() == 1 ? "-0" + month : "-" + month) + "-" + String.valueOf(i)));
                reportVO = getReportByTime(booleanBuilder, xqVO == null ? null : xqVO.getXqdm());
                result.add(reportVO);
            }
        });
        IntStream.range(now.getDayOfMonth(), now.lengthOfMonth() + 1).forEach((i) -> {
            result.add(new ReportVO());
        });
        withXq.put(xqVO == null ? "all" : xqVO.getXqmc(), result);
    }

    @Override
    public Result getBjlbPie(List<LocalDateTime> date, String pieXqdm) {
        QJcbBjBjlbb q = QJcbBjBjlbb.jcbBjBjlbb;

        QYwbJqJjjlb jj = QYwbJqJjjlb.ywbJqJjjlb;
        QYwbJqCjjlb cj = QYwbJqCjjlb.ywbJqCjjlb;
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        booleanBuilder.and(jj.jjbh.eq(cj.jjbh)).and(jj.jjbjlb.isNotNull()).and(jj.bjsj.gt(date.get(0))).and(jj.bjsj.lt(date.get(1)));
        if(pieXqdm != null) {
            booleanBuilder.and(jj.xqdm.eq(pieXqdm));
        }
        JPAQuery jpaQuery = queryFactory.select(Projections.bean(PieDTO.class, jj.jjlbmc.as("item"), jj.jjbjlb.count().as("count")))
                .from(jj, cj).where(booleanBuilder)
                .groupBy(jj.jjbjlb, jj.jjlbmc).fetchAll();
        List<PieDTO> result = jpaQuery.fetch();

        return Result.success(result);
    }

    @Override
    public Result getBjlxPolarintervalByBjlbmc(String bjlbmc, List<LocalDateTime> date, String pieXqdm) {
        QYwbJqJjjlb jj = QYwbJqJjjlb.ywbJqJjjlb;
        QYwbJqCjjlb cj = QYwbJqCjjlb.ywbJqCjjlb;
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        booleanBuilder.and(jj.jjbh.eq(cj.jjbh).and(jj.jjlbmc.eq(bjlbmc).and(jj.jjbjlb.isNotNull()).and(jj.bjsj.gt(date.get(0)).and(jj.bjsj.lt(date.get(1))))));
        if(pieXqdm != null) {
            booleanBuilder.and(jj.xqdm.eq(pieXqdm));
        }
        JPAQuery jpaQuery = queryFactory.select(Projections.bean(PieDTO.class, jj.jjlxmc.as("item"), jj.jjbjlx.count().as("count")))
                .from(jj, cj).where(booleanBuilder)
                .groupBy(jj.jjbjlx, jj.jjlxmc).fetchAll();
        List<PieDTO> result = jpaQuery.fetch();
        return Result.success(result);
    }

    @Override
    public Result getBjxlPyramidByBjlxmc(String bjlxmc, List<LocalDateTime> date, String pieXqdm) {
        QYwbJqJjjlb jj = QYwbJqJjjlb.ywbJqJjjlb;
        QYwbJqCjjlb cj = QYwbJqCjjlb.ywbJqCjjlb;
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        booleanBuilder.and(jj.jjbh.eq(cj.jjbh).and(jj.jjlxmc.eq(bjlxmc).and(jj.jjbjlb.isNotNull()).and(jj.bjsj.gt(date.get(0)).and(jj.bjsj.lt(date.get(1))))));
        if(pieXqdm != null) {
            booleanBuilder.and(jj.xqdm.eq(pieXqdm));
        }
        JPAQuery jpaQuery = queryFactory.select(Projections.bean(PieDTO.class, jj.jjxlmc.as("item"), jj.jjxlmc.count().as("count")))
                .from(jj, cj).where(booleanBuilder)
                .groupBy(jj.jjbjxl, jj.jjxlmc).fetchAll();
        List<PieDTO> result = jpaQuery.fetch();
        return Result.success(result);
    }
}